package com.tevintao.marketingsystem.services;

import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
import android.provider.Settings;
import android.text.TextUtils;

import com.tevintao.marketingsystem.activity.ActSetGps;
import com.tevintao.marketingsystem.aidl.ICallback;
import com.tevintao.marketingsystem.aidl.IMockMethod;
import com.tevintao.marketingsystem.log.LogManager;
import com.tevintao.marketingsystem.tool.PackageTool;
import com.tevintao.marketingsystem.xposted.HookDeviceModule;
import com.tevintao.marketingsystem.xposted.HookWebView;
import com.tevintao.marketingsystem.xposted.HookWindowManagerGlobal;

import org.json.JSONObject;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;


public class MockServices extends IMockMethod.Stub {

    public static final String TAG = MockServices.class.getSimpleName();

    public static final String SERVICE_NAME = MockServices.class.getSimpleName();
    private static MockServices mInstance;

    private static Context mContext;
    private static Thread mWorker = null;
    private static Handler mHandler = null;

    private static IMockMethod mClient = null;

    public MockServices() {
    }

    public static void register(ClassLoader classLoader, Object am) {
        mInstance = new MockServices();

        LogManager.getInstance().logHookInfo("MockServices register process id = " + Process.myUid());

        try {
            Class<?> cServiceManager = Class.forName("android.os.ServiceManager", false, classLoader);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                Method mAddService = cServiceManager.getDeclaredMethod("addService", String.class, IBinder.class,
                        boolean.class);
                mAddService.invoke(null, SERVICE_NAME, mInstance, true);
            } else {
                Method mAddService = cServiceManager.getDeclaredMethod("addService", String.class, IBinder.class);
                mAddService.invoke(null, SERVICE_NAME, mInstance);
            }
        } catch (Throwable throwable) {
            LogManager.getInstance().logHookError("MockServices register Throwable" + throwable.getMessage());
        }

        try {
            // Get context
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                Field fContext = null;
                Class<?> cam = am.getClass();
                while (cam != null && fContext == null)
                    try {
                        fContext = cam.getDeclaredField("mContext");
                    } catch (NoSuchFieldException ignored) {
                        cam = cam.getSuperclass();
                    }
                if (fContext == null)
                    LogManager.getInstance().logHookError(am.getClass().getName() + ".mContext not found");
                else {
                    fContext.setAccessible(true);
                    mContext = (Context) fContext.get(am);
                }
            }

            // Start a worker thread
            mWorker = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Looper.prepare();
                        mHandler = new Handler();
                        Looper.loop();
                    } catch (Throwable ex) {
                        LogManager.getInstance().logHookError("Start a worker thread " + ex);
                    }
                }
            });
            mWorker.start();
        } catch (Throwable throwable) {
            LogManager.getInstance().logHookError("MockServices register Throwable Get context" + throwable.getMessage());
        }
    }

    private Runnable mCheckTaskRunning = new Runnable() {
        @Override
        public void run() {
            mHandler.removeCallbacks(mCheckTaskRunning);
            if (mICallbacks.containsKey(TaskLogicService.TAG_CHECK_TASK_ALIVE)) {
                ICallback callback = mICallbacks.get(TaskLogicService.TAG_CHECK_TASK_ALIVE);
                try {
                    callback.callBack(new Bundle());
                } catch (DeadObjectException deadObjectException) {
                    deadObjectException.printStackTrace();
                    PackageTool.launchAppFormPackage(getContext(), HookDeviceModule.SELF_PACKAGE_NAME);
                } catch (RemoteException e) {
                    e.printStackTrace();
                    LogManager.getInstance().logError("mCheckTaskRunning e.getMessage() = " + e.getMessage());
                }
            }
            mHandler.postDelayed(mCheckTaskRunning, 30 * 1000);
        }
    };

    @Override
    public void startCheckTask() {
        mHandler.postDelayed(mCheckTaskRunning, 60 * 1000);
    }


    private HashMap<String, String> mStringMap = new HashMap<>();

    @Override
    public boolean putStringValue(String key, String value) throws RemoteException {
        mStringMap.put(key, value);
        return true;
    }

    @Override
    public String getStringValue(String key) throws RemoteException {
        return mStringMap.get(key);
    }



    private HashMap<String, Boolean> mBooleanMap = new HashMap<>();
    @Override
    public boolean putBooleanValue(String key, boolean value) throws RemoteException {
        return mBooleanMap.put(key,value);
    }

    @Override
    public boolean getBooleanValue(String key) throws RemoteException {
        return mBooleanMap.get(key);
    }


    public static boolean isRegistered() {
        return (mInstance != null);
    }

    public static boolean checkClient() {
        // Runs client side
        try {
            IMockMethod client = getClient();
            return client != null;
        } catch (SecurityException ignored) {
        } catch (Throwable ex) {
            LogManager.getInstance().logHookError("checkClient " + ex);
        }
        return false;
    }

    public static IMockMethod getClient() {
        // Runs client side
        if (mClient == null)
            try {
                // public static IBinder getService(String name)
                Class<?> cServiceManager = Class.forName("android.os.ServiceManager");
                Method mGetService = cServiceManager.getDeclaredMethod("getService", String.class);
                mClient = IMockMethod.Stub.asInterface((IBinder) mGetService.invoke(null, SERVICE_NAME));
            } catch (Throwable ex) {
                LogManager.getInstance().logHookError("checkClient  getClient " + ex);
            }
        return mClient;
    }

    private static HashMap<Integer, String> mPackageMap = new HashMap<>();


    @Override
    public String getPackageNameByUid(int uid) throws RemoteException {
        LogManager.getInstance().logInfo("getPackageNameByUid uid = " + uid + " context = " + getContext());

        if (mPackageMap.size() <= 0) {
            if (getContext() != null) {
                PackageManager pm = getContext().getPackageManager();
                List<PackageInfo> packageInfos = pm.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_PERMISSIONS);
                for (PackageInfo info : packageInfos) {
                    LogManager.getInstance().logInfo("packageName = " + info.packageName + " uid = " + info.applicationInfo.uid);
                    mPackageMap.put(info.applicationInfo.uid, info.packageName);
                }

            }
        }

        if (mPackageMap.containsKey(uid)) {
            return mPackageMap.get(uid);
        } else {
            return null;
        }
    }

    private static TreeSet<String> mSets = new TreeSet<>();

    @Override
    public boolean appAccessPath(String path) throws RemoteException {
        if (!mSets.contains(path))
            mSets.add(path);
        mHandler.postDelayed(mPrintInfo, 10000);
        return true;
    }


    @Override
    public String getDeviceJson() throws RemoteException {
        if (mICallbacks.containsKey(TaskLogicService.TAG_GET_CURRENT_DEVICE_INFO)) {
            ICallback callback = mICallbacks.get(TaskLogicService.TAG_GET_CURRENT_DEVICE_INFO);
            Bundle bundle = callback.callBack(new Bundle());
            String deviceInfo = bundle.getString(TaskLogicService.KEY_GET_CURRENT_DEVICE_INFO);
            if (TextUtils.isEmpty(deviceInfo)) {
                LogManager.getInstance().logError("Mockservice getDeviceJson updateDeviceJsonFromLocal json is null");
                return "";
            }
            return deviceInfo;
        }
        return "";
    }

    @Override
    public boolean setMobileDataEnable(boolean enable) throws RemoteException {
        mHandler.postDelayed(new SetMobileNetState(enable), 100);
        return true;
    }

    class SetMobileNetState implements Runnable {

        private boolean state;

        public SetMobileNetState(boolean state) {
            this.state = state;
        }

        @Override
        public void run() {
            boolean success = setNetState(state);
            LogManager.getInstance().logInfo("SetMobileNetState success = " + success);
        }
    }

    private boolean setNetState(boolean enable) {
        //5.0以上，禁用移动网络使用TelephonyManager#setDataEnabled
        //5.0以下，则是ConnectivityManager#setMobileDataEnabled
//        Object object = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? mContext.getSystemService(Context.TELEPHONY_SERVICE) :
//                mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
//        String methodName = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? "setDataEnabled" : "setMobileDataEnabled";
//        Method setMobileDataEnable;
//        try {
//            setMobileDataEnable = object.getClass().getDeclaredMethod(methodName, boolean.class);
//            setMobileDataEnable.setAccessible(true);
//            setMobileDataEnable.invoke(object, enable);
//            return true;
//        } catch (Exception e) {
//            LogManager.getInstance().logInfo("[setMobileDataEnable] error,exception:" + e.toString());
//            e.printStackTrace();
//            return false;
//        }

//        Settings.System.putInt(mContext.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, enable ? 1 : 0);
//        // 广播飞行模式信号的改变，让相应的程序可以处理。
//        // 不发送广播时，在非飞行模式下，Android 2.2.1上测试关闭了Wifi,不关闭正常的通话网络(如GMS/GPRS等)。
//        // 不发送广播时，在飞行模式下，Android 2.2.1上测试无法关闭飞行模式。
//        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
//        // intent.putExtra("Sponsor", "Sodino");
//        // 2.3及以后，需设置此状态，否则会一直处于与运营商断连的情况
//        intent.putExtra("state", enable);
//        mContext.sendBroadcast(intent);


        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, enable ? 1 : 0);
        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
        intent.putExtra("state", enable);
        mContext.sendBroadcast(intent);
        return true;
    }

    private static HashMap<String, String> mInfoMap = new HashMap<>();

    private double getLat() {
        if (mInfoMap.size() <= 0) {
            try {
                getLocationJson();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        if (mInfoMap.containsKey(ActSetGps.KEY_LAT)) {
            String lat = mInfoMap.get(ActSetGps.KEY_LAT);

            try {
                Double latD = Double.parseDouble(lat);
                return latD;
            } catch (NumberFormatException e) {
                e.printStackTrace();
                return 0;
            }
        }
        return 0f;
    }

    private double getLon() {
        if (mInfoMap.size() <= 0) {
            try {
                getLocationJson();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        if (mInfoMap.containsKey(ActSetGps.KEY_LON)) {
            String lon = mInfoMap.get(ActSetGps.KEY_LON);
            try {
                Double lonD = Double.parseDouble(lon);
                return lonD;
            } catch (NumberFormatException e) {
                e.printStackTrace();
                return 0;
            }
        }
        return 0f;
    }


    @Override
    public String getLocationJson() throws RemoteException {
        String decode = "";
        if (mICallbacks.containsKey(TaskLogicService.TAG_GET_CURRENT_LOCATION_INFO)) {
            ICallback callback = mICallbacks.get(TaskLogicService.TAG_GET_CURRENT_LOCATION_INFO);
            Bundle bundle = callback.callBack(new Bundle());
            decode = bundle.getString(TaskLogicService.KEY_GET_CURRENT_LOCATION_INFO);
        }

        if (TextUtils.isEmpty(decode)) {
            return "";
        } else {
            try {
                JSONObject jo = new JSONObject(decode);
                Iterator<String> keys = jo.keys();
                while (keys.hasNext()) {
                    String key = keys.next();
                    mInfoMap.put(key, jo.getString(key));
                }
            } catch (Exception e) {
                e.printStackTrace();
                LogManager.getInstance().logError("MockService getLocationJson updateHookJson " + e.getMessage());
            }

            LogManager.getInstance().logInfo("当前位置信息 = " + decode);
            return decode;
        }
    }

    @Override
    public boolean clearLocation() throws RemoteException {
        mInfoMap.clear();
        return true;
    }


    @Override
    public boolean canUseService(String name, String className) throws RemoteException {
//        LogManager.getInstance().logMockServicesInfo("canUseService name = " + name + " class name = " + className);
//        if (Context.WIFI_SERVICE.equals(name)) {
//            return false;
//        }
        return true;
    }


    private static final float DEFAULT_ACCURACY = 5.0f;
    private static final float DEFAULT_BEARING = 0.0f;
    private static final float DEFAULT_SPEED = 10f;
    private static final double DEFAULT_ALTITUDE = 0.0d; // 海拔

//    private float mLat = 0f;
//    private float mLon = 0f;
//    private float mAlt = 0f;


    @Override
    public Location getLocation(Location location) throws RemoteException {
//        if (System.currentTimeMillis() - mLastGetLocationTime > 10 * 1000) {
//            resetLocation();
//            mLastGetLocationTime = System.currentTimeMillis();
//            LogManager.getInstance().logInfo("getLocation from callback + mLastGetLocationTime = " + mLastGetLocationTime + " mLat = " + getLat() + " mLon = " + getLon() + " mAlt = " + DEFAULT_ALTITUDE);
//        }
        if (location == null) {
            location = new Location(LocationManager.GPS_PROVIDER);
            location.setAltitude(DEFAULT_ALTITUDE);
            location.setAccuracy(DEFAULT_ACCURACY);
            location.setBearing(DEFAULT_BEARING);
            location.setSpeed(DEFAULT_SPEED);
            location.setTime(System.currentTimeMillis());
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                location.setElapsedRealtimeNanos(System.currentTimeMillis());
            }
        }
        location.setLatitude(getLat());
        location.setLongitude(getLon());
        location.setAltitude(DEFAULT_ALTITUDE);

        return location;
    }

    public String getProcessName(int uid, int pid) throws RemoteException {
        if (null == getContext()) {
            LogManager.getInstance().logError("MockServices getProcessName null == getContext()");
            return "";
        }
        ActivityManager activityManager = (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> appProcessList = activityManager.getRunningAppProcesses();
        for (int i = 0; i < appProcessList.size(); i++) {
            ActivityManager.RunningAppProcessInfo appProcessInfo = appProcessList.get(i);
            //进程ID
            if (uid == appProcessInfo.uid && pid == appProcessInfo.pid) {
                return appProcessInfo.processName;
            }
        }
        return "";
    }

    @Override
    public boolean needMock(String packageName) throws RemoteException {
        if (HookDeviceModule.SELF_PACKAGE_NAME.equals(packageName)) {
            try {
                Field serial = Build.class.getField("SERIAL");
                serial.setAccessible(true);
                serial.set(null, "i am need needMock");
                LogManager.getInstance().logError("needMock i am need needMock");
                return true;
            } catch (Throwable ex) {
                LogManager.getInstance().logHookDeviceError("hookFiled error " + ex.getMessage());
            }
        }
        return false;
    }

    public static List<String> canRegisterProcessNames = Arrays.asList(AccountManager.WX_PACKAGE_NAME, "com.tevintao.marketingsystem", "com.android.settings");
//    private HashMap<String, IServiceCallback> mIServiceCallbacks = new HashMap<>();

//    @Override
//    public boolean registerCallback(String key, IServiceCallback callBack, int uid, int pid) throws RemoteException {
//        if (callBack != null) {
//            String processName = getProcessName(uid, pid);
//            if (canRegisterProcessNames.contains(processName)) {
//                LogManager.getInstance().logInfo("registerCallback key = " + key + " processName = " + processName);
//                mIServiceCallbacks.put(key, callBack);
//            }
//            return true;
//        }
//        return false;
//    }
//
//    @Override
//    public boolean unregisterCallback(String key, IServiceCallback callBack) throws RemoteException {
//        if (callBack != null) {
//            mIServiceCallbacks.remove(key);
//            return true;
//        }
//        return false;
//    }
//
//    @Override
//    public void sendCommand(String from, String key, Bundle bundle) throws RemoteException {
//        mHandler.post(new CommandRunnable(from, key, bundle));
//    }


    public static final String KEY_RESULT_CODE = "CALL_BACK_RESULT_CODE";

    public static final int CALL_SUCCESS_CODE = 0;
    public static final int CALL_PROCESS_DEAD_CODE = 1;
    public static final int CALL_UN_KNOW_ERROR = 2;
    public static final int CALL_NOT_FOUNT = 3;


    private HashMap<String, ICallback> mICallbacks = new HashMap<>();
    private List<ICallback> mGetViewCallbacks = new ArrayList<>(); //单独加入这两个，因为微信会有页面不在同一个进程，导致信息获取不到
    private List<ICallback> mDoEventCallbacks = new ArrayList<>();
    private List<ICallback> mGetWebViewCallbacks = new ArrayList<>();
    private List<ICallback> mDoScript = new ArrayList<>();

    @Override
    public boolean registerSyncCallback(String key, ICallback callBack, int uid, int pid) throws RemoteException {
        String processName = getProcessName(uid, pid);
        if (callBack != null) {
            if (HookWindowManagerGlobal.TAG_RETURN_GET_VIEW.equals(key)) {
                LogManager.getInstance().logInfo("many process registerCallback key = " + key + " uid = " + uid + " pid = " + pid + "processName = " + processName);
                mGetViewCallbacks.add(callBack);
                return true;
            } else if (HookWindowManagerGlobal.TAG_DO_VIEW_EVENT.equals(key)) {
                LogManager.getInstance().logInfo("many process registerCallback key = " + key + " uid = " + uid + " pid = " + pid + "processName = " + processName);
                mDoEventCallbacks.add(callBack);
                return true;
            } else if (HookWebView.TAG_GET_LAST_WEB_VIEW_HTML.equals(key)) {
                LogManager.getInstance().logInfo("many process registerCallback key = " + key + " uid = " + uid + " pid = " + pid + "processName = " + processName);
                mGetWebViewCallbacks.add(callBack);
                return true;
            } else if (HookWebView.TAG_DO_SCRIPT.equals(key)) {
                LogManager.getInstance().logInfo("many process registerCallback key = " + key + " uid = " + uid + " pid = " + pid + "processName = " + processName);
                mDoScript.add(callBack);
                return true;
            } else {
                if (canRegisterProcessNames.contains(processName)) {
                    LogManager.getInstance().logInfo("registerCallback key = " + key + " processName = " + processName);
                    mICallbacks.put(key, callBack);
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public boolean unregisterSyncCallback(String key, ICallback callBack) throws RemoteException {
        if (callBack != null) {
            mICallbacks.remove(key);
            return true;
        }
        return false;
    }

    @Override
    public Bundle getSyncBundle(String key, Bundle bundle) throws RemoteException {
        int code = CALL_SUCCESS_CODE;
        Bundle resultBundle = new Bundle();
        ICallback callback = mICallbacks.get(key);

        if (HookWindowManagerGlobal.TAG_RETURN_GET_VIEW.equals(key)) {
            LogManager.getInstance().logError("many process  mGetViewCallbacks size = " + mGetViewCallbacks.size());
            for (final ICallback iCallback : mGetViewCallbacks) {
                Bundle viewBundle = null;
                try {
                    viewBundle = iCallback.callBack(bundle);
                } catch (DeadObjectException deadObjectException) {
                    LogManager.getInstance().logError("getSyncBundle  deadObjectException " + deadObjectException.getMessage() + " mKey = " + key + " this.bundle = " + bundle);
                    code = CALL_PROCESS_DEAD_CODE;
                    deadObjectException.printStackTrace();
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            if (iCallback != null) {
                                LogManager.getInstance().logInfo("mDoEventCallbacks has errorCallback = " + iCallback);
                                mGetViewCallbacks.remove(iCallback);
                            }
                        }
                    });
                } catch (Throwable e) {
                    LogManager.getInstance().logError("getSyncBundle  Throwable " + e.getMessage() + " mKey = " + key + " this.bundle = " + bundle);
                    e.printStackTrace();
                    code = CALL_UN_KNOW_ERROR;
                }
                if (null != viewBundle) {
                    String jsonStr = viewBundle.getString(HookWindowManagerGlobal.KEY_VIEW_JSON_STRING);
//                        LogManager.getInstance().logInfo("KEY_VIEW_JSON_STRING jsonStr = " + jsonStr);
                    if (!TextUtils.isEmpty(jsonStr) && !"error".equals(jsonStr)) {
                        resultBundle = new Bundle(viewBundle);
                        code = CALL_SUCCESS_CODE;
                        break;
                    }
                }
            }

        } else if (HookWindowManagerGlobal.TAG_DO_VIEW_EVENT.equals(key)) {
            LogManager.getInstance().logError("many process mDoEventCallbacks size = " + mGetViewCallbacks.size());
            for (final ICallback iCallback : mDoEventCallbacks) {
                Bundle returnBundle = null;
                try {
                    returnBundle = iCallback.callBack(bundle);
                    LogManager.getInstance().logInfo("returnBundle = " + returnBundle);
                    resultBundle = new Bundle(returnBundle);
                } catch (DeadObjectException deadObjectException) {
                    LogManager.getInstance().logError("getSyncBundle  deadObjectException " + deadObjectException.getMessage() + " mKey = " + key + " this.bundle = " + bundle);
                    code = CALL_PROCESS_DEAD_CODE;
                    deadObjectException.printStackTrace();
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            if (iCallback != null) {
                                LogManager.getInstance().logInfo("mDoEventCallbacks has errorCallback = " + iCallback);
                                mDoEventCallbacks.remove(iCallback);
                            }
                        }
                    });
                } catch (Throwable e) {
                    LogManager.getInstance().logError("getSyncBundle  Throwable " + e.getMessage() + " mKey = " + key + " this.bundle = " + bundle);
                    e.printStackTrace();
                    code = CALL_UN_KNOW_ERROR;
                }

            }

        } else if (HookWebView.TAG_GET_LAST_WEB_VIEW_HTML.equals(key)) {
            LogManager.getInstance().logError("many process  mGetViewCallbacks size = " + mGetWebViewCallbacks.size());
            for (final ICallback iCallback : mGetWebViewCallbacks) {
                Bundle htmlBundle = null;
                try {
                    htmlBundle = iCallback.callBack(bundle);
                } catch (DeadObjectException deadObjectException) {
                    LogManager.getInstance().logError("getSyncBundle  deadObjectException " + deadObjectException.getMessage() + " mKey = " + key + " this.bundle = " + bundle);
                    code = CALL_PROCESS_DEAD_CODE;
                    deadObjectException.printStackTrace();
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            if (iCallback != null) {
                                LogManager.getInstance().logInfo("mDoEventCallbacks has errorCallback = " + iCallback);
                                mGetWebViewCallbacks.remove(iCallback);
                            }
                        }
                    });
                } catch (Throwable e) {
                    LogManager.getInstance().logError("getSyncBundle  Throwable " + e.getMessage() + " mKey = " + key + " this.bundle = " + bundle);
                    e.printStackTrace();
                    code = CALL_UN_KNOW_ERROR;
                }
                if (null != htmlBundle) {
//                    String jsonStr = htmlBundle.getString(HookWebView.KEY_GET_LAST_HTML);
////                        LogManager.getInstance().logInfo("KEY_VIEW_JSON_STRING jsonStr = " + jsonStr);
//                    if (!TextUtils.isEmpty(jsonStr) && !"error".equals(jsonStr)) {
//                        resultBundle = new Bundle(htmlBundle);
//                        code = CALL_SUCCESS_CODE;
//                        break;
//                    }
                }
            }
        } else if (HookWebView.TAG_DO_SCRIPT.equals(key)) {
            LogManager.getInstance().logError("many process mDoEventCallbacks size = " + mDoScript.size());
            for (final ICallback iCallback : mDoScript) {
                Bundle returnBundle = null;
                try {
                    returnBundle = iCallback.callBack(bundle);
                    LogManager.getInstance().logInfo("returnBundle = " + returnBundle);
                    resultBundle = new Bundle(returnBundle);
                } catch (DeadObjectException deadObjectException) {
                    LogManager.getInstance().logError("getSyncBundle  deadObjectException " + deadObjectException.getMessage() + " mKey = " + key + " this.bundle = " + bundle);
                    code = CALL_PROCESS_DEAD_CODE;
                    deadObjectException.printStackTrace();
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            if (iCallback != null) {
                                LogManager.getInstance().logInfo("mDoEventCallbacks has errorCallback = " + iCallback);
                                mDoScript.remove(iCallback);
                            }
                        }
                    });
                } catch (Throwable e) {
                    LogManager.getInstance().logError("getSyncBundle  Throwable " + e.getMessage() + " mKey = " + key + " this.bundle = " + bundle);
                    e.printStackTrace();
                    code = CALL_UN_KNOW_ERROR;
                }
            }
        } else if (null == callback) {
            code = CALL_NOT_FOUNT;
        } else {
            try {
                Bundle returnBundle = callback.callBack(bundle);
                resultBundle = new Bundle(returnBundle);
            } catch (DeadObjectException deadObjectException) {
                LogManager.getInstance().logError("getSyncBundle  deadObjectException " + deadObjectException.getMessage() + " mKey = " + key + " this.bundle = " + bundle);
                code = CALL_PROCESS_DEAD_CODE;
                deadObjectException.printStackTrace();
                mICallbacks.remove(callback);
            } catch (Throwable e) {
                LogManager.getInstance().logError("getSyncBundle  Throwable " + e.getMessage() + " mKey = " + key + " this.bundle = " + bundle);
                e.printStackTrace();
                code = CALL_UN_KNOW_ERROR;
            }
        }


        resultBundle.putInt(KEY_RESULT_CODE, code);
        return resultBundle;
    }


    private Runnable mPrintInfo = new Runnable() {
        @Override
        public void run() {
            mHandler.removeCallbacks(mPrintInfo);
            printAllPath();
            mHandler.postDelayed(mPrintInfo, 10000);
        }
    };

    private void printAllPath() {
        for (String path : mSets) {
            LogManager.getInstance().logInfo("printAllPath path = " + path);
        }
        LogManager.getInstance().logInfo("printAllPath path --------------------------------------------------------");
    }

    private Context getContext() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
            return mContext;
        else {
            // public static ActivityManagerService self()
            // frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
            try {
                Class<?> cam = Class.forName("com.android.server.am.ActivityManagerService");
                Object am = cam.getMethod("self").invoke(null);
                if (am == null)
                    return null;
                Field mContext = cam.getDeclaredField("mContext");
                mContext.setAccessible(true);
                return (Context) mContext.get(am);
            } catch (Throwable ex) {
                LogManager.getInstance().logHookError("getContext() " + ex.getMessage());
                return null;
            }
        }
    }

    public static String getProcessName() {
        if (MockServices.checkClient()) {
            try {
                return MockServices.getClient().getProcessName(Process.myUid(), Process.myPid());
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        return "";
    }


}
